<?php
/**
 * 对接Cloudflare R2 存储
 * 
 * @package CfR2 存储
 * @author 特控
 * @version 1.0.0
 * @link https://tj.tz520.cc
 */
if (!defined('__TYPECHO_ROOT_DIR__')) exit;

require_once dirname(__FILE__) . '/vendor/autoload.php';

use Aws\S3\S3Client;
use Aws\Credentials\Credentials;
use Typecho\Widget\Helper\Form;
use Typecho\Widget\Helper\Form\Element\Text;
use Typecho\Widget\Helper\Form\Element\Password;
use Typecho\Widget\Helper\Form\Element\Radio;
use Typecho\Widget\Helper\Form\Element\Submit;
use Typecho\Widget\Helper\Layout;
use Typecho\Plugin\PluginInterface;
use Typecho\Http\Client;
use Typecho\Date;

class R2Storage_Plugin implements PluginInterface
{
    /**
     * 激活插件
     */
    public static function activate()
    {
        \Typecho\Plugin::factory('Widget_Upload')->uploadHandle = [__CLASS__, 'uploadHandle'];
        \Typecho\Plugin::factory('Widget_Upload')->modifyHandle = [__CLASS__, 'modifyHandle'];
        \Typecho\Plugin::factory('Widget_Upload')->deleteHandle = [__CLASS__, 'deleteHandle'];
        \Typecho\Plugin::factory('Widget_Upload')->attachmentHandle = [__CLASS__, 'attachmentHandle'];
        \Typecho\Plugin::factory('admin/menu.php')->navBar = [__CLASS__, 'renderMenu'];
        
        return _t('R2存储插件已激活，请配置您的R2信息');
    }

    /**
     * 禁用插件
     */
    public static function deactivate()
    {
        return _t('R2存储插件已禁用');
    }

    /**
     * 插件配置面板
     */
    public static function config(Form $form)
    {
        require_once dirname(__FILE__) . '/Form.php';
        
        // 账户ID
        $accountId = new Text('accountId', null, '', _t('R2账户ID'), _t('您的Cloudflare账户ID，可在R2仪表板找到'));
        $form->addInput($accountId->addRule('required', _t('必须填写R2账户ID')));

        // 访问密钥
        $accessKeyId = new Text('accessKeyId', null, '', _t('访问密钥ID'));
        $form->addInput($accessKeyId->addRule('required', _t('必须填写访问密钥ID')));

        $accessKeySecret = new Text('accessKeySecret', null, '', _t('访问密钥'));
        $form->addInput($accessKeySecret->addRule('required', _t('必须填写访问密钥')));

        // 存储桶
        $bucketName = new Text('bucketName', null, '', _t('存储桶名称'));
        $form->addInput($bucketName->addRule('required', _t('必须填写存储桶名称')));

        // 自定义域名
        $customDomain = new Text('customDomain', null, '', _t('自定义域名（可选）'), 
            _t('例如：https://cdn.yourdomain.com<br>需先在Cloudflare配置CNAME解析到*.r2.cloudflarestorage.com'));
        $form->addInput($customDomain->addRule('url', _t('请输入有效的URL地址')));

        // 日志设置
        $enableLog = new Radio('enableLog', ['1' => _t('启用'), '0' => _t('禁用')], '0', _t('日志记录'));
        $form->addInput($enableLog);

        // 操作按钮
        $testButton = new R2Storage_Form_Element_TestButton('testButton', null, _t('测试连接'));
        $form->addItem($testButton);

        $logButton = new R2Storage_Form_Element_LogButton('logButton', null, _t('查看日志'));
        $form->addItem($logButton);
    }

    public static function personalConfig(Form $form) {}

    /**
     * 文件上传处理
     */
    public static function uploadHandle($file)
    {
        if (empty($file['name'])) return false;

        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!self::checkFileType($ext)) return false;

        $date = new Date(\Typecho\Widget::widget('Widget_Options')->gmtTime);
        $path = sprintf('%d/%02d/', $date->year, $date->month);
        $key = $path . uniqid() . '.' . $ext;

        try {
            $client = self::getS3Client();
            $client->putObject([
                'Bucket' => self::getOption('bucketName'),
                'Key' => $key,
                'Body' => fopen($file['tmp_name'], 'rb'),
                'ContentType' => $file['type'],
                'ACL' => 'public-read'
            ]);

            self::log("上传文件成功: {$key}");
            return [
                'name' => $file['name'],
                'path' => $key,
                'size' => $file['size'],
                'type' => $ext,
                'mime' => $file['type'],
                'url' => self::getFileUrl($key)
            ];
        } catch (\Exception $e) {
            self::log("上传失败: " . $e->getMessage(), 'ERROR');
            return false;
        }
    }

    /**
     * 文件修改处理
     */
    public static function modifyHandle($content, $file)
    {
        if (empty($file['name'])) return false;

        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if ($content['attachment']->type != $ext) return false;

        $key = $content['attachment']->path;

        try {
            $client = self::getS3Client();
            $client->putObject([
                'Bucket' => self::getOption('bucketName'),
                'Key' => $key,
                'Body' => fopen($file['tmp_name'], 'rb'),
                'ContentType' => $file['type'],
                'ACL' => 'public-read'
            ]);

            self::log("修改文件成功: {$key}");
            return [
                'name' => $content['attachment']->name,
                'path' => $key,
                'size' => $file['size'],
                'type' => $ext,
                'mime' => $file['type'],
                'url' => self::getFileUrl($key)
            ];
        } catch (\Exception $e) {
            self::log("修改失败: " . $e->getMessage(), 'ERROR');
            return false;
        }
    }

    /**
     * 文件删除处理
     */
    public static function deleteHandle($content)
    {
        try {
            $client = self::getS3Client();
            $client->deleteObject([
                'Bucket' => self::getOption('bucketName'),
                'Key' => $content['attachment']->path
               
            ]);
            self::log("删除文件成功: {$content['attachment']->path}");
            return true;
        } catch (\Exception $e) {
            self::log("删除失败: " . $e->getMessage(), 'ERROR');
            return false;
        }
    }

    /**
     * 获取附件URL
     */
    public static function attachmentHandle($content)
    {
        return self::getFileUrl($content['attachment']->path);
    }

    /**
     * 获取S3客户端实例（关键修改：固定使用R2原生端点）
     */
    private static function getS3Client()
    {
        static $client = null;
        
        if (!$client) {
            $credentials = new Credentials(
                self::getOption('accessKeyId'),
                self::getOption('accessKeySecret')
            );

            // 强制使用R2原生API端点（与自定义域名分离）
            $r2Endpoint = "https://" . self::getOption('accountId') . ".r2.cloudflarestorage.com";

            $client = new S3Client([
                'region' => 'auto',
                'endpoint' => $r2Endpoint,
                'version' => 'latest',
                'credentials' => $credentials,
                'use_path_style_endpoint' => false, // R2默认使用虚拟主机样式，无需路径风格
                'http' => [
                    'timeout' => 30,
                    'connect_timeout' => 5
                ]
            ]);
        }

        return $client;
    }

    /**
     * 获取文件访问URL（优化URL结构，移除Bucket名称）
     */
    private static function getFileUrl($key)
    {
        $key = ltrim($key, '/');
        $domain = self::getOption('customDomain');

        if ($domain) {
            // 使用自定义域名生成访问URL（CDN加速）
            return rtrim($domain, '/') . '/' . $key;
        }

        // 原生R2访问URL（无需包含Bucket名称）
        return sprintf("https://%s.r2.cloudflarestorage.com/%s",
            self::getOption('accountId'),
            $key
        );
    }

    /**
     * 获取插件配置项
     */
    private static function getOption($key)
    {
        static $options = null;
        
        if (!$options) {
            $options = \Typecho\Widget::widget('Widget_Options')->plugin('R2Storage');
        }

        return $options->$key ?? null;
    }

    /**
     * 检查文件类型
     */
    private static function checkFileType($ext)
    {
        $allowed = \Typecho\Widget::widget('Widget_Options')->allowedAttachmentTypes;
        return in_array($ext, (array)$allowed);
    }

    /**
     * 记录日志
     */
    private static function log($message, $level = 'INFO')
    {
        if (!self::getOption('enableLog')) return;

        $logDir = __TYPECHO_ROOT_DIR__ . '/usr/plugins/R2Storage/logs/';
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }

        $logFile = $logDir . date('Y-m-d') . '.log';
        file_put_contents($logFile, sprintf(
            "[%s] %s: %s\n",
            date('Y-m-d H:i:s'),
            $level,
            $message
        ), FILE_APPEND);
    }

    /**
     * 测试连接（验证R2端点可用性）
     */
    public static function testConnection()
    {
        try {
            // 验证自定义域名格式（仅用于访问，不影响上传端点）
            $customDomain = self::getOption('customDomain');
            if (!empty($customDomain) && !self::validateCustomDomain($customDomain)) {
                return [
                    'success' => false,
                    'message' => '自定义域名格式无效，需包含http://或https://'
                ];
            }

            $client = self::getS3Client();
            $client->listBuckets(); // 验证是否能访问R2端点

            return [
                'success' => true,
                'message' => '连接成功，R2存储桶可用'
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => '连接失败: ' . $e->getMessage()
            ];
        }
    }

    /**
     * 验证自定义域名
     */
    private static function validateCustomDomain($domain)
    {
        if (empty($domain)) return true;
        return filter_var($domain, FILTER_VALIDATE_URL) 
            && preg_match('/^https?:\/\//i', $domain);
    }

    /**
     * 渲染管理菜单
     */
    public static function renderMenu()
    {
        $options = \Typecho\Widget::widget('Widget_Options');
        $url = \Typecho\Common::url('/action/R2Storage-test', $options->index);
        
        echo <<<HTML
<script>
$(document).ready(function() {
    $(".typecho-page-title").after('<div class="r2-storage-test-result" style="margin:10px;padding:10px;display:none"></div>');
    
    $("#testButton").click(function(e) {
        e.preventDefault();
        $.post("{$url}", function(data) {
            var div = $(".r2-storage-test-result");
            div.show().removeClass().addClass(data.success ? "success" : "error")
               .html("<strong>" + (data.success ? "✓ 成功" : "✗ 失败") + "</strong>: " + data.message);
        }, "json");
    });
});
</script>
<style>
.r2-storage-test-result.success { background:#f0f9eb; color:#67c23a; border:1px solid #e1f3d8 }
.r2-storage-test-result.error { background:#fef0f0; color:#f56c6c; border:1px solid #fde2e2 }
</style>
HTML;
    }
}

// 注册测试路由
\Typecho\Plugin::factory('action')->R2Storage_test = ['R2Storage_Plugin', 'testConnection'];